iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
自我挑戰組

模仿知名網站的外觀系列 第 13

【Day13】模仿知名網站的外觀 Instagram(13) 搜尋區塊

  • 分享至 

  • xImage
  •  

我們上一次完成了Story區塊,但是只能透過網址進入,這一次我們要設定能從首頁上進入Story。

修改StoryCircle.jsx,增加點擊跳到Story的功能。

import React from "react";
import { useNavigate } from "react-router-dom";

const StoryCircle = () => {
	const navigate = useNavigate();

	const handleNavigate = () => {
		navigate("/story");
	};
	return (
		<div
			onClick={handleNavigate}
			className="cursor-pointer flex flex-col items-center"
		>
			<img
				className="w-16 h-16 rounded-full"
				src="https://images.pexels.com/photos/7106845/pexels-photo-7106845.jpeg?auto=compress"
				alt=""
			/>
			<p>username</p>
		</div>
	);
};

export default StoryCircle;

接著,我們要完成搜尋區塊。

在Components資料夾底下,新增SearchComponents資料夾。

在SearchComponents資料夾下,新增SearchComponents.jsx、SearchComponents.css。

SearchComponents.jsx的內容如下:

import React from "react";
import "./SearchComponents.css";

const SearchComponents = () => {
	return (
		<div className="searchContainer">
			<div>
				<h1>Search</h1>
				<input className="searchInput" type="text" placeholder="Search" />
			</div>
		</div>
	);
};

export default SearchComponents;

有一個大標題和一個輸入區塊。

SearchComponents.css

.searchContainer{
    padding: 1rem 0rem;
    border: 1px solid rgb(222, 222, 222);
    box-shadow: 0 1px 2px rgb(2, 2, 2);
    width: 300px;
    height: 100vh;
    z-index: 10;
}

.searchInput{
    border: none;
    border-radius: 4px;
    background-color: rgb(242, 242, 242);
    padding: 5px 10px;
    font-size: 12px;
    width: 100%;
    outline: none;
    margin-left: 10px;
}

來到Sidebar.jsx,設定按下Search後顯示搜尋區塊。

import React, { useState } from "react";
import { IoReorderThreeOutline } from "react-icons/io5";
import { menu } from "./SidebarMenu";
import { useNavigate } from "react-router-dom";
import { useDisclosure } from "@chakra-ui/react";
import CreatePostModal from "../Post/CreatePostModal";
import SearchComponents from "../SearchComponents/SearchComponents";

const Sidebar = () => {
	const [activeTab, setActiveTab] = useState([]);
	const navigate = useNavigate();
	const { isOpen, onOpen, onClose } = useDisclosure();
	const [isSearchVisible, setIsSearchVisible] = useState(false);

	const handleTabClick = (title) => {
		setActiveTab(title);
		//點擊Profile按鈕時,跳到/username
		if (title === "Profile") {
			navigate("/username");
		}
		//點擊Home按鈕時,跳到/
		else if (title === "Home") {
			navigate("/");
		}
		//點擊Create按鈕時,跳出CreateModal視窗
		else if (title === "Create") {
			onOpen();
		}

		if(title === "Search"){
			setIsSearchVisible(true)
		}
		else{
			setIsSearchVisible(false)
		}
	};

	return (
		<div className="sticky top-0 h-[100vh] flex">
			<div className="flex flex-col justify-between h-full px-10">
				<div>
					<div className="pt-10">
						<img className="w-40" src="Instagram_logo.svg.png" alt="" />
					</div>
					<div className="mt-10">
						{menu.map((item) => (
							<div
								onClick={() => handleTabClick(item.title)}
								className="flex items-center cursor-pointer mb-5 text-lg"
							>
								{activeTab === item.title ? item.activeIcon : item.icon}
								<p
									className={`${
										activeTab === item.title ? "font-bold" : "font-semibold"
									}`}
								>
									{item.title}
								</p>
							</div>
						))}
					</div>
				</div>
				<div className="flex items-center cursor-pointer pb-10">
					<IoReorderThreeOutline />
					<p className="ml-5">More</p>
				</div>
			</div>
			<CreatePostModal onClose={onClose} isOpen={isOpen} />

			{isSearchVisible && <SearchComponents />}
		</div>
	);
};

export default Sidebar;

被兩條黑色的邊界線包圍的就是我們的搜尋區塊。

Untitled

當搜尋區塊顯示時,左側的導航列的文字應該會消失,修改Sidebar.jsx符合這個規則。

import React, { useState } from "react";
import { IoReorderThreeOutline } from "react-icons/io5";
import { menu } from "./SidebarMenu";
import { useNavigate } from "react-router-dom";
import { useDisclosure } from "@chakra-ui/react";
import CreatePostModal from "../Post/CreatePostModal";
import SearchComponents from "../SearchComponents/SearchComponents";

const Sidebar = () => {
	const [activeTab, setActiveTab] = useState([]);
	const navigate = useNavigate();
	const { isOpen, onOpen, onClose } = useDisclosure();
	const [isSearchVisible, setIsSearchVisible] = useState(false);

	const handleTabClick = (title) => {
		setActiveTab(title);
		//點擊Profile按鈕時,跳到/username
		if (title === "Profile") {
			navigate("/username");
		}
		//點擊Home按鈕時,跳到/
		else if (title === "Home") {
			navigate("/");
		}
		//點擊Create按鈕時,跳出CreateModal視窗
		else if (title === "Create") {
			onOpen();
		}

		if (title === "Search") {
			setIsSearchVisible(true);
		} else {
			setIsSearchVisible(false);
		}
	};

	return (
		<div className="sticky top-0 h-[100vh] flex">
			<div className="flex flex-col justify-between h-full px-10">
				<div>
					<div className="pt-10">
						<img className="w-40" src="Instagram_logo.svg.png" alt="" />
					</div>
					<div className="mt-10">
						{menu.map((item) => (
							<div
								onClick={() => handleTabClick(item.title)}
								className="flex items-center cursor-pointer mb-5 text-lg"
							>
								{activeTab === item.title ? item.activeIcon : item.icon}
								{!(activeTab === "Search") && (
									<p
										className={`${
											activeTab === item.title ? "font-bold" : "font-semibold"
										}`}
									>
										{item.title}
									</p>
								)}
							</div>
						))}
					</div>
				</div>
				<div className="flex items-center cursor-pointer pb-10">
					<IoReorderThreeOutline />
					{!(activeTab === "Search") && <p className="ml-5">More</p>}
				</div>
			</div>
			<CreatePostModal onClose={onClose} isOpen={isOpen} />

			{isSearchVisible && <SearchComponents />}
		</div>
	);
};

export default Sidebar;

修改排版和當搜尋欄開啟時Instagram logo應該要消失。

import React, { useState } from "react";
import { IoReorderThreeOutline } from "react-icons/io5";
import { menu } from "./SidebarMenu";
import { useNavigate } from "react-router-dom";
import { useDisclosure } from "@chakra-ui/react";
import CreatePostModal from "../Post/CreatePostModal";
import SearchComponents from "../SearchComponents/SearchComponents";

const Sidebar = () => {
	const [activeTab, setActiveTab] = useState([]);
	const navigate = useNavigate();
	const { isOpen, onOpen, onClose } = useDisclosure();
	const [isSearchVisible, setIsSearchVisible] = useState(false);

	const handleTabClick = (title) => {
		setActiveTab(title);
		//點擊Profile按鈕時,跳到/username
		if (title === "Profile") {
			navigate("/username");
		}
		//點擊Home按鈕時,跳到/
		else if (title === "Home") {
			navigate("/");
		}
		//點擊Create按鈕時,跳出CreateModal視窗
		else if (title === "Create") {
			onOpen();
		}

		if (title === "Search") {
			setIsSearchVisible(true);
		} else {
			setIsSearchVisible(false);
		}
	};

	return (
		<div className="sticky top-0 h-[100vh] flex">
			<div
				className={`flex flex-col justify-between h-full ${
					activeTab === "Search" ? "px-2" : "px-10"
				}`}
			>
				<div>
					{!(activeTab === "Search") && (
						<div className="pt-10">
							<img className="w-40" src="Instagram_logo.svg.png" alt="" />
						</div>
					)}
					<div className="mt-10">
						{menu.map((item) => (
							<div
								onClick={() => handleTabClick(item.title)}
								className="flex items-center cursor-pointer mb-5 text-lg"
							>
								{activeTab === item.title ? item.activeIcon : item.icon}
								{!(activeTab === "Search") && (
									<p
										className={`${
											activeTab === item.title ? "font-bold" : "font-semibold"
										}`}
									>
										{item.title}
									</p>
								)}
							</div>
						))}
					</div>
				</div>
				<div className="flex items-center cursor-pointer pb-10">
					<IoReorderThreeOutline />
					{!(activeTab === "Search") && <p className="ml-5">More</p>}
				</div>
			</div>
			<CreatePostModal onClose={onClose} isOpen={isOpen} />

			{isSearchVisible && <SearchComponents />}
		</div>
	);
};

export default Sidebar;

Untitled

修改SearchComponents.css,讓搜尋輸入的區塊不要超出搜尋欄。

.searchContainer{
    padding: 1rem 0rem;
    border: 1px solid rgb(222, 222, 222);
    box-shadow: 0 1px 2px rgb(2, 2, 2);
    width: 300px;
    height: 100vh;
    z-index: 10;
}

.searchInput{
    border: none;
    border-radius: 4px;
    background-color: rgb(242, 242, 242);
    padding: 5px 10px;
    font-size: 12px;
    width: 90%;
    outline: none;
    margin-left: 10px;
}

調整一下排版,SearchComponents.jsx。

import React from "react";
import "./SearchComponents.css";

const SearchComponents = () => {
	return (
		<div className="searchContainer">
			<div className="px-3 pb-5">
				<h1 className="text-xl pb-5">Search</h1>
				<input className="searchInput" type="text" placeholder="Search" />
			</div>

			<hr />

			<div>
				
			</div>
		</div>
	);
};

export default SearchComponents;

Untitled

我們的搜尋欄還缺了一些東西,就是搜尋結果。

在SearchComponents資料夾下,新增SearchCard.jsx。

import React from "react";

const SearchCard = () => {
	return (
		<div className="py-2 cursor-pointer">
			<div className="flex items-center">
				<img
					className="w-10 h-10 rounded-full"
					src="https://images.pexels.com/photos/15784572/pexels-photo-15784572.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"
					alt=""
				/>

				<div className="ml-3">
					<p>FullName</p>
					<p className="opacity-70">username</p>
				</div>
			</div>
		</div>
	);
};

export default SearchCard;

在SearchComponents.jsx,顯示SearchCard的內容。

import React from "react";
import "./SearchComponents.css";
import SearchCard from "./SearchCard";

const SearchComponents = () => {
	return (
		<div className="searchContainer">
			<div className="px-3 pb-5">
				<h1 className="text-xl pb-5">Search</h1>
				<input className="searchInput" type="text" placeholder="Search" />
			</div>

			<hr />

			<div className="px-3 pt-5">
				{[1, 1, 1, 1, 1, 1].map((item) => <SearchCard />)}
			</div>
		</div>
	);
};

export default SearchComponents;

Untitled

我們模仿Instagram的部分就到此結束了,雖然還有Explore、Reels、Message、Notification沒完成,不過需要的技術我們已經使用過了,Explore使用Profile區塊的Post程式碼再加上一些CSS就能完成了。Reels使用HomeRight的SuggestionCard的程式碼在加上一些排版就能做出雛形。Message、Notification這種會出現側邊欄的東西,我們已經在做SearchComponents時用過了。

下回我們會模擬另外一個知名的網站。


上一篇
【Day12】模仿知名網站的外觀 Instagram(12) Story區塊
下一篇
【Day14】模仿知名網站的外觀 X(1) 創建專案
系列文
模仿知名網站的外觀30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言